local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
local LSM = LibStub('LibSharedMedia-3.0')
local lbf = LibStub("LibButtonFacade", true)
local AceGUI = LibStub("AceGUI-3.0")

local L = famBags.L
local db = nil

-- :::::::::::: LOCALS ::::::::::::: -------------------------------------------------------------------------

local fix_hpad = {
   CENTER = 0,
   LEFT = 0,
   RIGHT = -2
}

local fix_vpad = {
   CENTER = 1,
   TOP = -1,
   BOTTOM = 2,
}

local function get_point(h, v, px, py)
   py = py or px
   local align
   local hpad = px + fix_hpad[h]
   local vpad = py + fix_vpad[v]
   if v == 'CENTER' then
      vpad = fix_vpad[v]
      v = ''
   end
   if h == 'CENTER' then
      hpad = fix_hpad[h]
      h = ''
   end
   if h..v == '' then
      align = 'CENTER'
   else
      align = v..h
   end
   if h == 'RIGHT' then hpad = -hpad end
   if v == 'TOP' then vpad = -vpad end
   return align, hpad, vpad
end

local function copy_table(from, to)
   for k, v in pairs(from) do
      if type(v) == 'table' then
         to[k] = to[k] or {}
         copy_table(from[k], to[k])
      else
         to[k] = v
      end
   end
end

local function get_value_index(arr, value, field)
   for i,v in pairs(arr) do
      if field then
         if v[field] == value then return i end
      else
         if v == value then return i end
      end
   end
   return nil
end

local DEFAULT_FONT = select(1, SystemFont_Small:GetFont())
local CATEGORIES_DROPDOWN_ITEMS = {
   [0] = {
      text = L['Move to category'],
      value = L['Move to category'],
      isTitle = true,
      notCheckable = true,
   }
}

local ITEMACTIONS_DROPDOWN_ITEMS = {}

StaticPopupDialogs['FAMBAGS_APPLYDEFAULPRESET'] = {
  text = L['FAMBAGS_APPLYDEFAULPRESET'],
  button1 = OKAY,
  button2 = CANCEL,
  OnAccept = function() famBags:ApplyDefaultCategory() end,
  timeout = 0,
  whileDead = true,
  hideOnEscape = true,
  enterClicksFirstButton = false,
}

StaticPopupDialogs['FAMBAGS_CONFIRMSECTIONSELL'] = {
  text = L['FAMBAGS_CONFIRMSECTIONSELL'],
  button1 = OKAY,
  button2 = CANCEL,
  OnAccept = function() famBags:UseSectionItems() end,
  timeout = 0,
  whileDead = true,
  hideOnEscape = true,
  enterClicksFirstButton = false,
}


-- :::::::::::: famBags ::::::::::::: -------------------------------------------------------------------------

function famBags:InitLayoutVars()
   db = self.db.profile
end

function famBags:InitMoveToCategoryMenu()
   if not famBags.MoveToCategoryDD.button then return end
   local i = 1
   local db = db.categoriesV2
   local id = famBags.MoveToCategoryDD.button.info.id
   UIDropDownMenu_AddButton(CATEGORIES_DROPDOWN_ITEMS[0])
   for catindex, c in ipairs(famBags.SortedCategories.all) do
      CATEGORIES_DROPDOWN_ITEMS[i] = CATEGORIES_DROPDOWN_ITEMS[i] or {}

      CATEGORIES_DROPDOWN_ITEMS[i].text = c
      CATEGORIES_DROPDOWN_ITEMS[i].value = catindex
      CATEGORIES_DROPDOWN_ITEMS[i].arg1 = catindex
      CATEGORIES_DROPDOWN_ITEMS[i].arg2 = id
      CATEGORIES_DROPDOWN_ITEMS[i].colorCode = nil
      CATEGORIES_DROPDOWN_ITEMS[i].notCheckable = true
      CATEGORIES_DROPDOWN_ITEMS[i].func = famBags.MoveToCategory

      if db[catindex].Items and db[catindex].Items[id] then
         CATEGORIES_DROPDOWN_ITEMS[i].text = c..' '..L['[clear]']
         CATEGORIES_DROPDOWN_ITEMS[i].arg1 = 'clear'
         CATEGORIES_DROPDOWN_ITEMS[i].colorCode = '|cfff4d626'
      end

      UIDropDownMenu_AddButton(CATEGORIES_DROPDOWN_ITEMS[i])
      i = i + 1
   end
end

function famBags:InitItemActionsMenu()
   local b = famBags.ItemActionsDD.button
   if not b then return end
   local i = 1
   if b.info.spell and strtrim(b.info.spell) ~= '' and tContains(famBags.BagIndexes.bags, b.info.bag) then
      ITEMACTIONS_DROPDOWN_ITEMS[i] = ITEMACTIONS_DROPDOWN_ITEMS[i] or {}
      ITEMACTIONS_DROPDOWN_ITEMS[i].text = 'Use'
      ITEMACTIONS_DROPDOWN_ITEMS[i].value = 'use'

      ITEMACTIONS_DROPDOWN_ITEMS[i].arg1 = b
      ITEMACTIONS_DROPDOWN_ITEMS[i].arg2 = nil
      ITEMACTIONS_DROPDOWN_ITEMS[i].colorCode = nil
      ITEMACTIONS_DROPDOWN_ITEMS[i].notCheckable = true
      UIDropDownMenu_AddButton(ITEMACTIONS_DROPDOWN_ITEMS[i])
      famBags:CreateDummyButtonForItemUse(b)
      i = i + 1
   end
   if b.info.count and b.info.count > 1 then
      ITEMACTIONS_DROPDOWN_ITEMS[i] = ITEMACTIONS_DROPDOWN_ITEMS[i] or {}
      ITEMACTIONS_DROPDOWN_ITEMS[i].text = 'Split'
      ITEMACTIONS_DROPDOWN_ITEMS[i].value = 'split'
      ITEMACTIONS_DROPDOWN_ITEMS[i].arg1 = b
      ITEMACTIONS_DROPDOWN_ITEMS[i].arg2 = nil
      ITEMACTIONS_DROPDOWN_ITEMS[i].colorCode = nil
      ITEMACTIONS_DROPDOWN_ITEMS[i].notCheckable = true
      ITEMACTIONS_DROPDOWN_ITEMS[i].func = famBags.ItemAction_Split
      UIDropDownMenu_AddButton(ITEMACTIONS_DROPDOWN_ITEMS[i])
      i = i + 1
   end
end

function famBags:ItemAction_Split(b)
   OpenStackSplitFrame(b.info.count, b, "BOTTOMRIGHT", "TOPRIGHT");
end

function famBags:CreateDummyButtonForItemUse(item)
   local listFrame = _G["DropDownList1"];
   local index = listFrame and (listFrame.numButtons + 1) or 1;
   local listFrameName = listFrame:GetName();
   local buttonDD = _G[listFrameName.."Button"..listFrame.numButtons];

   local b = _G["famBagsSecureDummyButtonForItemUse"]
   if not b then
      b = CreateFrame("Button", "famBagsSecureDummyButtonForItemUse", UIParent, "SecureActionButtonTemplate")
      b:SetAttribute("type", "macro")
      b:SetScript('OnEnter', function(self) _G[self.dd:GetName().."Highlight"]:Show() end)
      b:SetScript('OnLeave', function(self) _G[self.dd:GetName().."Highlight"]:Hide() end)
   end
   b.dd = buttonDD
   b:ClearAllPoints()
   b:SetParent(buttonDD:GetParent())
   b:SetHeight(UIDROPDOWNMENU_BUTTON_HEIGHT)
   for i = 1, buttonDD:GetNumPoints() do
      b:SetPoint(buttonDD:GetPoint(i))
   end
   b:SetPoint('RIGHT', listFrame, 'RIGHT', 0, 0)
   b:SetFrameLevel(buttonDD:GetFrameLevel() + 1)
   b:SetAttribute("macrotext", '/cast '..string.match(item.info.link, "item[%-?%d:]+")..'\n/run CloseDropDownMenus(1); _G[\'famBagsSecureDummyButtonForItemUse\']:Hide()')
   b:Show()
end

function famBags:PositionBagFromDB(frame, anchor, db)
   self:PositionBag(frame, anchor, db.halign, db.valign, db.hspacing, db.vspacing)
end

function famBags:PositionBag(frame, anchor, halign, valign, x, y)
   local align, h, v = get_point(halign, valign, x, y)
   frame:ClearAllPoints()
   frame:SetPoint(align, anchor, align, h, v)
end

function famBags:UpdateBags()
   if (not self.famBagsFrame) or self.CHANGING_PROFILE then
      self.famBagsFrame = self:CreateBagFrame('famBagsFrame', L['famBags'], UIParent, 4, 300, 300, db.mainwindow, true)
      self:PositionBag(self.famBagsFrame, UIParent, db.mainwindow.layout.halign, db.mainwindow.layout.valign, db.mainwindow.layout.hspacing, db.mainwindow.layout.vspacing)
      self.famBagsFrame:Hide()
      self.MAINFRAMES['bags'] = self.famBagsFrame
      self.famBankFrame = self:CreateBagFrame('famBankFrame', L['Bank'], UIParent, 4, 300, 300, db.bank, true)
      self:PositionBag(self.famBankFrame, UIParent, db.bank.layout.halign, db.bank.layout.valign, db.bank.layout.hspacing, db.bank.layout.vspacing)
      self.famBankFrame:Hide()
      self.MAINFRAMES['bank'] = self.famBankFrame
      self:UpdateMoneyFrame()
      self:UpdateBlizzardBankFrame()
      if db.bagswindow.enabled then
         self:UpdateBagSlotsFrame()
      end
   end
   self:UpdatePlayerBags()
   self.LDBBags:Update()
   self.LDBCurrency:Update()
   if not self.CHANGING_PROFILE and db.layout.general.sections == 'categories' then
      if not next(db.categoriesV2) then
         StaticPopup_Show("FAMBAGS_APPLYDEFAULPRESET")
      elseif not self.db.global.version or self.db.global.version < 010207 then
         StaticPopupDialogs['FAMBAGS_APPLYDEFAULPRESET'].text = L['FAMBAGS_APPLYDEFAULPRESETOLDDATA']
         StaticPopup_Show("FAMBAGS_APPLYDEFAULPRESET")
      end
   end
   self.db.global.version = self.CURRENT_VERSION
end

function famBags:ApplyDefaultCategory()
   if LoadAddOn('famBagsOptions') then
      local famBagsOptions = LibStub('AceAddon-3.0'):GetAddon('famBagsOptions')
      famBagsOptions:ApplyPreset(6, 3)
   end
end

function famBags:UpdateMoneyFrame()
   if db.money.enabled then
      if not self.famBagsMoneyFrame then
         self.famBagsMoneyFrame = self:CreateMoneyFrame(db.money)
      end
      self.famBagsMoneyFrame:Show()
   else
      if self.famBagsMoneyFrame then
         self.famBagsMoneyFrame:Hide()
      end
   end
end

function famBags:UpdateBlizzardBankFrame()
   if db.bankwindow.enabled then
      if not self.famBagsBlizzardBankFrame then
         self.famBagsBlizzardBankFrame = self:CreateBlizzardBankFrame(db.bankwindow)
         self.famBagsBlizzardBankFrame:Hide()
      end
      --self.famBagsBlizzardBankFrame:Show()
   elseif self.famBagsBlizzardBankFrame then
      self.famBagsBlizzardBankFrame:Hide()
   end
end

function famBags:UpdateBagSlotsFrame()
   if not self.famBagsBagSlotsFrame then
      self.famBagsBagSlotsFrame = self:CreateBagSlotsFrame(db.bagswindow)
   end
   if self.famBagsBagSlotsFrame.KeyRingTexture then
      self.famBagsBagSlotsFrame.KeyRingTexture:SetTexCoord(0, 0.5625, 0, 0.609375)
   end
   self.famBagsBagSlotsFrame:Hide()
end

function famBags:UpdatePlayerBags(bag)
   if not bag then
      self.Sections:CreateEmpty('bags')
      self.Sections:CreateEmpty('bank')
      self.Sections:BuildBagsSections('bags')
      self.Sections:BuildBagsSections('bank')

      if self.FIRST_BUILD then
         self.ticktime = 2
         self:StartTimer()
      end
   else
      print('Create Empty --> ', bag)
      self.Sections:CreateEmpty(bag)
      self.Sections:BuildBagsSections(bag)
   end
   if self.CHANGING_PROFILE or bag then
      self.BAGS_NEED_LAYOUT = true
      self:UpdateAllButtons(bag)
      famBags:LayoutBagsButtons(bag)
   end
end

function famBags:UpdateBagButtons(bag, slots, forceIndicators, skipUpdate)
   local frame = (tContains(famBags.BagIndexes.bags, bag)) and 'bags' or 'bank'
   if not slots then
      if not self.MAINFRAMES[frame].offline then
         slots = GetContainerNumSlots(bag)
      elseif self.dbButtons[self.CURRENT_PLAYER[frame]][bag] then
         slots = #self.dbButtons[self.CURRENT_PLAYER[frame]][bag]
      end
   end
   if slots then
      for i=1, slots do
         self.Buttons:Create(bag, i, forceIndicators, skipUpdate)
      end
   end
end

function famBags:UpdateEmptiesButtons(bag)
   if not self.EMPTIES_NEED_LAYOUT[bag] then return end
   if db.layout.general.sections ~= 'bags' or bag == 'bags' then
      famBags.Buttons:CreateEmpty(0, bag, 0)
   else
      famBags.Buttons:CreateEmpty(BANK_CONTAINER, bag, 0)
   end
   for n in pairs(famBags.Buttons.empties[bag]) do
      if n ~= 0 or (db.layout.general.sections == 'bags' and bag == 'bank') then
         famBags.Buttons.empties[bag][n].info.needUpdate = true
      end
   end
   local n, bagType
   for _, i in ipairs(self.BagIndexes[bag]) do
      if not famBags.MAINFRAMES[bag].offline then
         n, bagType = GetContainerNumFreeSlots(i)
      else
         bagType = 0
      end
      if i == KEYRING_CONTAINER then
         bagType = 256
      elseif not (bagType and famBags.BagTypes[bagType]) then
         bagType = 0
      end
      if db.layout.general.sections ~= 'bags' then
         if bagType ~= 0 then
            local b = famBags.Buttons:CreateEmpty(bagType, bag, bagType)
            b.info.needUpdate = nil
         end
      else
         local b = famBags.Buttons:CreateEmpty(i, bag, bagType)
         b.info.needUpdate = nil
      end
      if not famBags.Buttons[i] then
         famBags.Buttons:CreateBag(i)
      end
      famBags.Buttons[i].bagType = bagType
   end
   famBags:LayoutEmptiesButtons(bag)
   self.EMPTIES_NEED_LAYOUT[bag] = nil
end

function famBags:LayoutEmptiesButtons(bag)
   if not (famBags.Buttons.empties and famBags.Buttons.empties[bag]) then return end
   local b1
   famBags.Sections[bag].empties:SetHeight((rawget(famBags.Buttons.empties[bag], next(famBags.Buttons.empties[bag])):GetHeight() + (db.layout.buttons.vpadding * 2)) * db.layout.buttons.size)
   if db.layout.general.sections ~= 'bags' then
      b1 = famBags:LayoutEmptiesButton(bag, famBags.Buttons.empties[bag][0], nil, 0, true)
      for n, b in pairs(famBags.Buttons.empties[bag]) do
         if n ~= 0 then
            if b.info.needUpdate then
               b = b:GetParent():Hide() -- dummyparent
               famBags.Buttons.empties[bag][n] = nil
            else
               b1 = famBags:LayoutEmptiesButton(bag, b, b1, n, nil)
            end
         end
      end
   else
      for n, b in pairs(famBags.Buttons.empties[bag]) do
         if b.info.needUpdate then
            b = b:GetParent():Hide() -- dummyparent
            famBags.Buttons.empties[bag][n] = nil
         end
      end
      local b
      local first = true
      for _, i in ipairs(self.BagIndexes[bag]) do
         b = famBags.Buttons.empties[bag][i]
         b1 = famBags:LayoutEmptiesButton(bag, b, b1, i, first)
         first = nil
      end
   end
end

function famBags:LayoutEmptiesButton(bag, b, b1, i, first)
   local count
   local db = db.layout
   if first then
      count = _G[b:GetName().."Count"]
      self:SetTextLayout(b, count, db.counts, nil, false, false)
      b = b:GetParent()
      b:ClearAllPoints()
      b:SetPoint('TOP'..db.empties.hpos, self.Sections[bag].empties, 'TOP'..db.empties.hpos, (db.empties.hpos == 'LEFT') and db.buttons.hpadding or -db.buttons.hpadding, -db.buttons.vpadding)
   else
      count = _G[b:GetName().."Count"]
      self:SetTextLayout(b, count, db.counts, nil, false, false)
      b = b:GetParent() -- dummyparent
      b:ClearAllPoints()
      b:SetPoint('TOP'..db.empties.hpos, b1, 'TOP'..(db.empties.hpos == 'LEFT' and 'RIGHT' or 'LEFT'), (db.empties.hpos == 'LEFT') and db.buttons.hspacing or -db.buttons.hspacing, 0)
   end
   b:SetScale(db.buttons.size)
   return b
end

function famBags:UpdateAllButtons(bag)
   if not bag or bag == 'bags' then
      for _, i in ipairs(self.BagIndexes['bags']) do
         self:UpdateBagButtons(i)
      end
   end
   if not bag or bag == 'bank' then
      for _, i in ipairs(self.BagIndexes['bank']) do
         if self.Buttons[i] then
            self:UpdateBagButtons(i, #self.Buttons[i], nil, true)
         end
      end
   end
   self.CHANGING_PROFILE = nil
end

function famBags:LightLayoutBagsButtons(bag)
   if bag == 'bank' and (not self.famBankFrame:IsVisible()) then return end
   self:UpdateEmptiesButtons(bag)
   if db.layout.general.sections == 'categories' then
      famBags.Buttons:UpdateCurrentFromCategories(bag)
   else
      famBags.Buttons:UpdateCurrentFromBags(bag, db.layout.general.sections == 'onebag')
   end
end

function famBags:LayoutBagsButtons(bag)
   if db.layout.general.sections == 'onebag' then
      if bag then
         self:LayoutButtonsAsOneBag(bag)
      else
         self:LayoutButtonsAsOneBag('bags')
         self:LayoutButtonsAsOneBag('bank')
      end
   else
      if bag then
         self:LayoutButtonsBySections(bag)
      else
         self:LayoutButtonsBySections('bags')
         self:LayoutButtonsBySections('bank')
      end
   end
   self.BAGS_LOADED = true
end

function famBags:LayoutButtonsBySections(bag)
   if bag == 'bank' and (not self.famBankFrame:IsVisible()) then
      return
   end
   self:UpdateEmptiesButtons(bag)
   local max_x_row = db[(bag == 'bags') and 'mainwindow' or 'bank'].layout.buttons_x_row
   local hp = db.layout.buttons.hpadding
   local vp = db.layout.buttons.vpadding
   local hs = db.layout.buttons.hspacing
   local vs = db.layout.buttons.vspacing
   local size = db.layout.buttons.size
   local ordered = db.layout.order.ordered
   local sectionsType = db.layout.general.sections

   famBags.Buttons:ClearAllPoints(bag)
   if sectionsType == 'categories' then
      self.Buttons:BuildCurrentFromCategories(bag, ordered)
   else
      self.Buttons:BuildCurrentFromBags(bag, ordered, false)
   end

   local bw = nil
   local bh = nil
   for i, buttons in pairs(self.Buttons.Current[bag]) do
      local slots = #buttons
      if slots and slots > 0 and self.Sections[bag][sectionsType][i] then
         local section = self.Sections[bag][sectionsType][i]
         if sectionsType == 'bags' then
            self.Sections:SetTitle(sectionsType, section, GetBagName(section.name))
         end

         local rowpos = 1
         local maxrowpos = 1
         local rows = 1
         local th = section.titleFrame:GetHeight()
         local ti = vp
         local dbsection = db.sections[(sectionsType == 'bags') and 'bags' or i]
         local ox
         local oy
         if dbsection.title.is_inset then
            th = th + dbsection.title.inset + vp
            ti = th
         end
         for j=1, slots do
            if rowpos > maxrowpos then
               maxrowpos = rowpos
            end
            local b = buttons[j]
            if (not bw) then
               bw = b:GetWidth()
               bh = b:GetHeight()
            end
            ox = hp + ((rowpos-1) * (hs + bw))
            oy = -(ti + ((rows-1) * (vs + bh)))
            b:SetPoint('TOPLEFT', section.bodyFrame, 'TOPLEFT', ox, oy)
            for _, b1 in ipairs(b.stacks) do
               b1:SetPoint('TOPLEFT', section.bodyFrame, 'TOPLEFT', ox, oy)
            end
            if rowpos >= max_x_row and j > 1 and j < slots then
               rows = rows + 1
               rowpos = 0
            end
            if sectionsType ~= 'categories' or not db.minimized_sections[bag][section.name] then
               b:Show()
            end
            rowpos = rowpos + 1
         end
         local tw = section.titleFrame.titleText:GetWidth()
         local w
         if sectionsType ~= 'categories' or not db.minimized_sections[bag][section.name] then
            w = ((bw * maxrowpos) + (hs * (maxrowpos - 1)) + (hp * 2)) * size
            section:SetWidth(w)
            section:SetHeight(th + (((bh * rows) + (vs * (rows - 1)) + (vp * 2)) * size))
         else
            w = tw + (dbsection.title.text.padding * 2)
            section:SetWidth(w)
            section:SetHeight(th - ((dbsection.title.is_inset) and vp or 0))
         end
         if w < tw + (dbsection.title.text.padding * 2) then
            local h = section.titleFrame.titleText:GetHeight()
            section.titleFrame.titleText:SetWidth(w - (dbsection.title.text.padding * 2))
            section.titleFrame.titleText:SetHeight(h)
         end
         section:Show()
      elseif self.Sections[bag][sectionsType][i] then
         self.Sections[bag][sectionsType][i]:Hide()
      end
   end
   if not self.isStackMode then
      self.Sections[bag].empties:Hide()
   end
   famBags.Sections:LayoutBags(bag, sectionsType)
end

function famBags:LayoutButtonsAsOneBag(bag)
   if bag == 'bank' and (not self.famBankFrame:IsVisible()) then
      return
   end
   self:UpdateEmptiesButtons(bag)
   local max_x_row = db[(bag == 'bags') and 'mainwindow' or 'bank'].layout.buttons_x_row
   local hp = db.layout.buttons.hpadding
   local vp = db.layout.buttons.vpadding
   local hs = db.layout.buttons.hspacing
   local vs = db.layout.buttons.vspacing
   local size = db.layout.buttons.size
   local ordered = db.layout.order.ordered

   famBags.Buttons:ClearAllPoints(bag)
   for _, i in ipairs(famBags.BagIndexes[bag]) do
      if self.Sections[bag]['bags'] and self.Sections[bag]['bags'][i] then
         self.Sections[bag]['bags'][i]:Hide()
      end
   end

   self.Buttons:BuildCurrentFromBags(bag, ordered, true)
   local buttons = self.Buttons.Current[bag]

   local rowpos = 1
   local maxrowpos = 1
   local rows = 1
   local bw = 0
   local bh = 0
   local dbbag = (bag == 'bags') and 'mainwindow' or 'bank'
   local f = (bag == 'bags') and famBags.famBagsFrame or famBags.famBankFrame
   local th = f.titleFrame:GetHeight()
   local ti = 0
   if db[dbbag].title.is_inset then
      th = th + (db[dbbag].title.inset)
      ti = th
   end
   if famBags.isStackMode then
      local dbe = db.layout.empties
      local s = famBags.Sections[bag].empties
      s:ClearAllPoints()
      s:SetPoint(dbe.vpos..'LEFT', f.bodyFrame, dbe.vpos..'LEFT', dbe.hpadding, (dbe.vpos == 'TOP') and -(ti + dbe.vpadding) or dbe.vpadding)
      s:SetPoint('RIGHT', f.bodyFrame, 'RIGHT', -dbe.hpadding, 0)
      if dbe.vpos == 'TOP' then
         ti = ti + s:GetHeight()/size + dbe.vpadding
      end
      th = th + s:GetHeight() + dbe.vpadding
      s:Show()
   end
   for i=1, #buttons do
      maxrowpos = max(maxrowpos, rowpos)
      local b = buttons[i]
      if i == 1 then
         b:SetPoint('TOPLEFT', f.bodyFrame, 'TOPLEFT', hp, -(vp + ti))
         bw = b:GetWidth()
         bh = b:GetHeight()
      elseif rowpos == 1 then
         b:SetPoint('TOPLEFT', buttons[i - max_x_row], 'BOTTOMLEFT', 0, -vs)
         rows = rows + 1
      else
         b:SetPoint('TOPLEFT', buttons[i-1], 'TOPRIGHT', hs, 0)
         if rowpos == max_x_row then
            rowpos = 0
         end
      end
      b:Show()
      rowpos = rowpos + 1
   end
   local dbw = famBags.db.profile[dbbag].layout
   if dbw.fixed_width then
      f:SetWidth(((bw * dbw.buttons_x_row) + (hs * (dbw.buttons_x_row - 1)) + (hp * 2)) * size)
   else
      f:SetWidth(((bw * maxrowpos) + (hs * (maxrowpos - 1)) + (hp * 2)) * size)
   end
   f:SetHeight((th + ((bh * rows) + (vs * (rows - 1)) + (vp * 2))) * size)
   if bag == 'bags' then
      self:UpdateInputFrame(self.BagsSearchFrame, db.mainwindow.search)
      if self.OFFLINE_ENABLED then
         self:UpdateInputFrame(self.BagsAltsFrame, db.mainwindow.alts)
      end
   else
      self:UpdateInputFrame(self.BankSearchFrame, db.bank.search)
      if self.OFFLINE_ENABLED then
         self:UpdateInputFrame(self.BankAltsFrame, db.bank.alts)
      end
   end
end

function famBags:OptimizeStacks(bag)
   local o = self.OPTIMIZATION
   local b
   if not o.inProgress then
      for _, i in ipairs(self.BagIndexes[bag]) do
         if i ~= KEYRING_CONTAINER then
            for _, b in ipairs(self.Buttons[i]) do
               if b.info.id and b.info.stack > 1 and b.info.count < b.info.stack then
                  table.insert(o.set, b)
               end
            end
         end
      end
      sort(
         o.set,
         function(b1,b2)
            if b1.info.id ~= b2.info.id then
               return b1.info.id < b2.info.id
            else
               return b1.info.count > b2.info.count
            end
         end)

      o.inProgress = true
      o.bag = bag
      o.index = 1
      o.subIndex = 0

      self:StartOptimizationProgress(bag)
   end

   local b1
   local l1, l2

   local count = #o.set
   while o.index < count do
      b = o.set[o.index]
      if o.subIndex < 1 then
         o.subIndex = o.index
      end
      while b.info.count < b.info.stack do
         o.subIndex = o.subIndex + 1
         if o.subIndex > count or o.set[o.subIndex].info.id ~= b.info.id then
            break
         end
         b1 = o.set[o.subIndex]
         local _, _, l1 = GetContainerItemInfo(b.info.bag, b.info.slot)
         local _, _, l2 = GetContainerItemInfo(b1.info.bag, b1.info.slot)
         if l1 or l2 then
            o.subIndex = o.subIndex - 1
            self.ticktime = 0.1
            self:StartTimer()
            return
         end
         b.info.count = b.info.count + b1.info.count
         PickupContainerItem(b1.info.bag, b1.info.slot)
         PickupContainerItem(b.info.bag, b.info.slot)
         ClearCursor()
         if b.info.count > b.info.stack then
            b1.info.count = b.info.count - b.info.stack
         end
         self:SetOptimizationProgress(bag, o.subIndex/count)
         self.ticktime = 0.005
         self:StartTimer()
         return
      end
      self:SetOptimizationProgress(bag, o.index/count)
      o.index = o.subIndex
      o.subIndex = 0
      self.ticktime = 0.005
      self:StartTimer()
      return
   end
   o.inProgress = false
   wipe(o.set)
   self:StopOptimizationProgress(bag)
   self.ticktime = db.layout.general.update_time
   self:StartTimer()
end

function famBags:CreateBagFrame(name, title, parent, startLevel, w, h, db, movable)
   local f = (_G[name]) and _G[name] or CreateFrame('Frame', name, parent)

   if movable then
      f:SetMovable(true)
      f:EnableMouse(true)
      f:RegisterForDrag('LeftButton')
      f:SetScript('OnMouseDown', function(f, button)
         if button ~= 'LeftButton' then return end
         f.pOrigin = f.pOrigin or {}
         f.pOrigin.point, f.pOrigin.anchor, f.pOrigin.relPoint, f.pOrigin.x, f.pOrigin.y = f:GetPoint(1)
         f:StartMoving()
         f.pStart = f.pStart or {}
         f.pStart.x, f.pStart.y = select(4, f:GetPoint(1))
      end)
      f:SetScript('OnMouseUp', function(f, button)
         if button ~= 'LeftButton' then return end
         f.pEnd = f.pEnd or {}
         f.pEnd.x, f.pEnd.y = select(4, f:GetPoint(1))
         f:StopMovingOrSizing()
         f:ClearAllPoints()
         local x = f.pOrigin.x + (f.pEnd.x - f.pStart.x)
         local y = f.pOrigin.y + (f.pEnd.y - f.pStart.y)
         f:SetPoint(f.pOrigin.point, f.pOrigin.anchor, f.pOrigin.relPoint, x, y)
         if db.layout.persist_pos then
            db.layout.hspacing = math.abs(x)
            db.layout.vspacing = math.abs(y)
         end
      end)
   end

   f:SetFrameStrata(self.db.profile.layout.general.strata)

   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetWidth(w)
   f:SetHeight(h)

   f.bodyFrame = f.bodyFrame or CreateFrame('Frame', name..'_Body', f)
   if f.bodyFrame:GetEffectiveScale() == 1 then
      f.bodyFrame:SetScale(UIParent:GetEffectiveScale())
   end
   f.bodyFrame:SetFrameLevel(startLevel)
   self:SetFrameBackdrop(f.bodyFrame, db)

   if db.title then
      f.titleFrame = f.titleFrame or CreateFrame('Frame', name..'_Title', f)
      if f.titleFrame:GetEffectiveScale() == 1 then
         f.titleFrame:SetScale(UIParent:GetEffectiveScale())
      end
      f.titleFrame:SetFrameLevel(startLevel + 1)
      self:SetFrameBackdrop(f.titleFrame, db.title)
      self:SetTextLayout(f.titleFrame, 'titleText', db.title.text, title, true, false)
      self:SetTitleInset(f, db.title.is_inset, db.title.inset, db.title.text.padding)
   else
      f.bodyFrame:SetAllPoints(f)
   end

   return f
end

function famBags:SetTextLayout(frame, fontstring, db, text, autoheightparent, autowidthparent)
   local t
   if type(fontstring) == 'string' then
      if not frame[fontstring] then
         frame[fontstring] = frame:CreateFontString(nil, 'OVERLAY');
         frame[fontstring].autoheight = autoheightparent
         frame[fontstring].autowidth = autowidthparent
      end
      t = frame[fontstring]
   else
      t = fontstring
   end

   local flags = ''
   for n, v in pairs(db.flags) do
      if n ~= 'SHADOW' and v then
         if flags ~= '' then
            flags = flags..', '
         end
         flags = flags..n
      end
   end
   t:SetFont(LSM:Fetch('font', db.font or '') or DEFAULT_FONT, db.size, flags)
   if db.flags.SHADOW then
      t:SetShadowColor(0, 0, 0, 1)
      t:SetShadowOffset(0.8, -0.8)
   elseif t:GetShadowOffset() then
      t:SetShadowColor(0, 0, 0, 0)
      t:SetShadowOffset(0, 0)
   end

   t:SetWidth(0)
   t:SetHeight(0)
   t:ClearAllPoints()
   local align, h, v = get_point(db.halign, db.valign, db.padding)
   t:SetPoint(align, frame, align, h, v);
   if text ~= nil then
      t.text = text
   end
   if t.text then
      t:SetText(string.format('|cff%02x%02x%02x%s|r', db.color[1]*255, db.color[2]*255, db.color[3]*255, t.text));
   end

   if t.autoheight then
      frame:SetHeight(t:GetHeight() + db.padding*2 + 1)
   end

   if t.autowidth then
      frame:SetWidth(t:GetWidth() + db.padding*2)
   elseif frame:GetWidth() > 0 and frame:GetWidth() < t:GetWidth() + db.padding*2 then
      t:SetWidth(frame:GetWidth() - db.padding*2)
      t:SetHeight(frame:GetHeight() - db.padding*2)
   end
end

function famBags:SetTitleInset(frame, is_inset, inset, padding)
   frame.titleFrame:ClearAllPoints()
   frame.bodyFrame:ClearAllPoints()
   if is_inset then
      frame.titleFrame:SetPoint('TOPLEFT', frame, 'TOPLEFT', inset, -inset)
      frame.titleFrame:SetPoint('RIGHT', frame, 'RIGHT', -inset, 0)
      frame.titleFrame:SetHeight(frame.titleFrame.titleText:GetHeight() + (padding*2) + 1)
      frame.bodyFrame:SetAllPoints(frame)
   else
      frame.titleFrame:SetPoint('TOPLEFT', frame, 'TOPLEFT', 0, 0)
      frame.titleFrame:SetHeight(frame.titleFrame.titleText:GetHeight() + (padding*2) + 1)
      if frame.titleFrame.titleText.autowidth then
         frame.titleFrame:SetWidth(frame.titleFrame.titleText:GetWidth() + (padding*2))
      else
         frame.titleFrame:SetPoint('RIGHT', frame, 'RIGHT', 0, 0)
      end
      frame.bodyFrame:SetPoint('TOPLEFT', frame.titleFrame, 'BOTTOMLEFT', 0, 0)
      frame.bodyFrame:SetPoint('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', 0, 0)
   end
end

function famBags:SetFrameBackdrop(frame, db)
   if not frame.bg then
      frame.bg = frame:CreateTexture(nil, 'BACKGROUND')
   end
   local t = frame.bg
   t:SetTexture(1,1,1,1)
   if db.bg.type == 1 then --[[ Solid--]]
      t:SetGradientAlpha('VERTICAL',
         db.bg.color1[1], db.bg.color1[2], db.bg.color1[3], db.bg.color1[4],
         db.bg.color1[1], db.bg.color1[2], db.bg.color1[3], db.bg.color1[4])
   elseif db.bg.type == 2 then --[[ Vertical gradient--]]
      t:SetGradientAlpha('VERTICAL',
         db.bg.color1[1], db.bg.color1[2], db.bg.color1[3], db.bg.color1[4],
         db.bg.color2[1], db.bg.color2[2], db.bg.color2[3], db.bg.color2[4])
   elseif db.bg.type == 3 then --[[ Horizontal gradient--]]
      t:SetGradientAlpha('HORIZONTAL',
         db.bg.color1[1], db.bg.color1[2], db.bg.color1[3], db.bg.color1[4],
         db.bg.color2[1], db.bg.color2[2], db.bg.color2[3], db.bg.color2[4])
   elseif db.bg.type == 4 then --[[ Texture--]]
      t:SetTexture(LSM:Fetch('background', db.bg.texture))
      t:SetVertexColor(unpack(db.bg.color1))
   end
 --   if frame:GetName() == 'famBagsFrame_Title' then
 --      dump('db', db)
 --   end
   --db.bg.inset = db.bg.inset or 0
   t:SetPoint('TOPLEFT', frame, 'TOPLEFT', db.bg.inset, -db.bg.inset)
   t:SetPoint('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -db.bg.inset, db.bg.inset)
   -- SetBackdrop only for border
   frame:SetBackdrop(
      {edgeFile = LSM:Fetch('border', db.bg.br_texture),
       edgeSize = db.bg.br_size});
   frame:SetBackdropBorderColor(unpack(db.bg.br_color));
end

function famBags:GetMoney()
   local copper = GetMoney()
   local money
   if self.OFFLINE_ENABLED then
      money = self.dbButtons[self.PLAYER_NAME].money
      money.money = copper
   end
   local size = db.money.text.size + 1
   local t = string.format('%d|TInterface\\MoneyFrame\\UI-GoldIcon:%d:%d:3:0:64:64:4:60:4:60|t ', copper / 100 / 100, size, size)
   if db.money.show_silver then
      t = t..string.format(' %d|TInterface\\MoneyFrame\\UI-SilverIcon:%d:%d:3:0:64:64:4:60:4:60|t ', (copper / 100) % 100, size, size)
   end
   if db.money.show_copper then
      t = t..string.format(' %d|TInterface\\MoneyFrame\\UI-CopperIcon:%d:%d:3:0:64:64:4:60:4:60|t ', copper % 100, size, size)
   end

   for i=1, GetCurrencyListSize() do
      local name, isHeader, _, _, isWatched, count, icon = GetCurrencyListInfo(i)
      if (not isHeader) then
         if isWatched then
            t = (count or 0)..'|T'..icon..':'..size..':'..size..':3:0:64:64:4:60:4:60|t   '..t
         end
         if money then
            money[i] = count
         end
      end
   end

   return t
end

function famBags:GetOfflineMoney()
   local money = self.dbButtons[self.CURRENT_PLAYER['bags']].money
   if not (money and money.money) then return '' end
   local size = db.money.text.size + 1
   local t = string.format('%d|TInterface\\MoneyFrame\\UI-GoldIcon:%d:%d:3:0:64:64:4:60:4:60|t ', money.money / 100 / 100, size, size)
   if db.money.show_silver then
      t = t..string.format(' %d|TInterface\\MoneyFrame\\UI-SilverIcon:%d:%d:3:0:64:64:4:60:4:60|t ', (money.money / 100) % 100, size, size)
   end
   if db.money.show_copper then
      t = t..string.format(' %d|TInterface\\MoneyFrame\\UI-CopperIcon:%d:%d:3:0:64:64:4:60:4:60|t ', money.money % 100, size, size)
   end

   for i=1, GetCurrencyListSize() do
      local name, isHeader, _, _, isWatched, _, icon = GetCurrencyListInfo(i)
      if (not isHeader) then
         if isWatched and money[i] then
            t = (money[i] or 0)..'|T'..icon..':'..size..':'..size..':3:0:64:64:4:60:4:60|t   '..t
         end
      end
   end

   return t
end

function famBags:CreateMoneyFrame(db)
   local f = _G['famBagsMoneyFrame'] or CreateFrame('Frame', 'famBagsMoneyFrame', self.famBagsFrame)
   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetPoint('TOPLEFT', self.famBagsFrame, 'BOTTOMLEFT', 0, 0)
   f:SetPoint('RIGHT', self.famBagsFrame, 'RIGHT', 0, 0)
   f:SetHeight(10)
   f:EnableMouse(true)
   f:SetScript('OnMouseUp', function(f, button)
      if button == 'LeftButton' and not famBags.famBagsFrame.offline then
         MoneyInputFrame_OpenPopup(UIParent)
      end
   end)
   self:SetFrameBackdrop(f, db)

   self:SetTextLayout(f, 'moneyText', db.text, self:GetMoney(), true, false)

   return f
end

function famBags:CreateBlizzardBankFrame(db)
   local f
   if _G['famBagsBlizzardBankFrame'] then
      f = _G['famBagsBlizzardBankFrame']
      self:SetFrameBackdrop(f, db)
      return f
   end

   f = CreateFrame('Frame', 'famBagsBlizzardBankFrame', self.famBankFrame)
   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetPoint('TOPLEFT', self.famBankFrame, 'BOTTOMLEFT', 0, 0)
   f:SetPoint('RIGHT', self.famBankFrame, 'RIGHT', 0, 0)
   self:SetFrameBackdrop(f, db)

   f.BankBags = {}
   for i=1, 7 do
      local b = 'BankFrameBag'..i
      f.BankBags[i] = _G[b]
      f.BankBags[i]:SetParent(f)
      f.BankBags[i]:ClearAllPoints()
      if lbf and famBags.BFBags then
         famBags.BFBags:AddButton(f.BankBags[i],{
            Icon = _G[b.."IconTexture"]
         })
      end
   end
   f:SetHeight(f.BankBags[1]:GetHeight() + 10)
   f.BankBags[4]:SetPoint('CENTER', f, 'CENTER', 0, 0)
   f.BankBags[4]:SetPoint('TOP', f, 'TOP', 0, -10)
   f.BankBags[3]:SetPoint('TOPRIGHT', f.BankBags[4], 'TOPLEFT', -5, 0)
   f.BankBags[2]:SetPoint('TOPRIGHT', f.BankBags[3], 'TOPLEFT', -5, 0)
   f.BankBags[1]:SetPoint('TOPRIGHT', f.BankBags[2], 'TOPLEFT', -5, 0)
   f.BankBags[5]:SetPoint('TOPLEFT', f.BankBags[4], 'TOPRIGHT', 5, 0)
   f.BankBags[6]:SetPoint('TOPLEFT', f.BankBags[5], 'TOPRIGHT', 5, 0)
   f.BankBags[7]:SetPoint('TOPLEFT', f.BankBags[6], 'TOPRIGHT', 5, 0)


   f.PurchaseInfo = _G['BankFramePurchaseInfo']
   local _, full = GetNumBankSlots()
   if not full then
      f.PurchaseInfo:SetParent(f)
      f.PurchaseInfo:SetPoint('CENTER', f, 'CENTER', -10, 0)
      f.PurchaseInfo:SetPoint('BOTTOM', f, 'BOTTOM', 0, -5)
      f:SetHeight(f:GetHeight() + f.PurchaseInfo:GetHeight())
   else
      f:SetHeight(f:GetHeight() + 10)
   end

   return f
end

function famBags:CreateBagSlotsFrame(db)
   local f
   if _G['famBagsBagSlotsFrame'] then
      f = _G['famBagsBagSlotsFrame']
      self:SetFrameBackdrop(f, db)
      return f
   end

   f = CreateFrame('Frame', 'famBagsBagSlotsFrame', self.famBagsFrame)
   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetPoint('TOPRIGHT', self.famBagsFrame, 'TOPLEFT', 0, 0)
   self:SetFrameBackdrop(f, db)

   f.BagSlots = {}

   local function hack_slot(i, name)
      f.BagSlots[i] = _G[name]
      f.BagSlots[i]:SetParent(f)
      f.BagSlots[i]:ClearAllPoints()
      if lbf and famBags.BFBags then
         if i ~= KEYRING_CONTAINER then
            famBags.BFBags:AddButton(f.BagSlots[i],{
               Icon = _G[name.."IconTexture"]
            })
         else
            f.KeyRingTexture = f.BagSlots[i]:GetNormalTexture()
            famBags.BFBags:AddButton(f.BagSlots[i],{
               Icon = f.KeyRingTexture
            })
         end
      end
   end

   for i=0, NUM_BAG_SLOTS do
      local name = (i > 0) and 'CharacterBag'..(i-1)..'Slot' or 'MainMenuBarBackpackButton'
      hack_slot(i, name)
      if i > 0 then
         f.BagSlots[i]:SetPoint('TOPLEFT', f.BagSlots[i-1], 'BOTTOMLEFT', 0, (i > 1) and -3 or -4)
      else
         f.BagSlots[i]:SetPoint('TOPLEFT', f, 'TOPLEFT', 6, -6)
      end
   end

   --hack_slot(KEYRING_CONTAINER, 'KeyRingButton')
   --f.BagSlots[KEYRING_CONTAINER]:SetPoint('TOPLEFT', f.BagSlots[1], 'TOPRIGHT', 2, 0)
   local bs = f.BagSlots[1]:GetWidth() + 12
   f.BagSlots[0]:SetScale(bs / f.BagSlots[0]:GetWidth())

   f:SetWidth(bs + 15)
   f:SetHeight(bs + ((f.BagSlots[1]:GetHeight() + 3) * NUM_BAG_SLOTS) + 16)

   return f
end

function famBags:CreateCheckButton(name, frame, tnormal, tpushed, tchecked, thighlight, tooltip, onclick, checked)
   local b = CreateFrame('CheckButton', name, frame, 'ChatConfigCheckButtonTemplate')
   b:SetFrameLevel(7)
   b:SetNormalTexture(tnormal)
   b:SetPushedTexture(tpushed)
   b:SetCheckedTexture(tchecked)
   b:SetHighlightTexture(thighlight)
   local dt = b:CreateTexture()
   dt:SetTexture(tnormal)
   dt:SetDesaturated(true)
   dt:SetAllPoints()
   b:SetDisabledTexture(dt)
   b:SetHitRectInsets(4,4,4,4)
   b.tooltip = tooltip
   if checked ~= nil then
      b:SetChecked(checked)
   end
   b:SetScript("OnClick", onclick)

   return b
end

function famBags:CreateNormalButton(name, frame, onclick, tnormal, tpushed, thighlight, tooltip)
   local b = CreateFrame('Button', name, frame, 'UIPanelCloseButton')
   b:SetHitRectInsets(4,4,4,4)
   b:SetFrameLevel(7)
   b:SetScript("OnClick", onclick)
   if tnormal then
      b:SetNormalTexture(tnormal)
      b:SetPushedTexture(tpushed)
      b:SetHighlightTexture(thighlight)
      local dt = b:CreateTexture()
      dt:SetTexture(tnormal)
      dt:SetDesaturated(true)
      dt:SetAllPoints()
      b:SetDisabledTexture(dt)
      b.tooltip = tooltip
   end
   b:SetScript("OnEnter",
      function(self)
         if (self.tooltip) then
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, (self.tooltipStyle or 1))
         end
      end)
   b:SetScript("OnLeave",
      function(self)
         GameTooltip:Hide()
      end)

   return b
end

function famBags:CreateIntefaceButtons()
   local db = db.layout.actions
   self.BagsCloseButton = self.BagsCloseButton or self:CreateNormalButton(
      'famBagsBagsCloseButton',
      famBags.famBagsFrame,
      function(self)
         local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
         famBags:HideBags()
      end)
   self.BagsCloseButton:SetPoint('TOPRIGHT', famBags.famBagsFrame.titleFrame, 'TOPRIGHT', 4, 4)
   self.BagsCloseButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
   self.BagsCloseButton:SetPoint('LEFT', famBags.famBagsFrame.titleFrame, 'RIGHT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
   self.BagsCloseButton:Show()
   local anchorframe = self.BagsCloseButton

   if db.stack then
      self.BagsStackButton = self.BagsStackButton or self:CreateCheckButton(
         'famBagsBagsStackButton',
         famBags.famBagsFrame,
         'Interface\\Addons\\famBags\\Textures\\btnnostack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnnostack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnstack.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Stacking mode on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.isStackMode = self:GetChecked()
            famBags.db.profile.stackmode = famBags.isStackMode or false
            famBags.BankStackButton:SetChecked(self:GetChecked())
            famBags:LayoutBagsButtons()
         end,
         self.isStackMode)
      self.BagsStackButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsStackButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsStackButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsStackButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsStackButton:Show()
      anchorframe = self.BagsStackButton
   elseif self.BagsStackButton then
      self.BagsStackButton:Hide()
   end

   if db.refresh then
      self.BagsRefreshButton = self.BagsRefreshButton or self:CreateNormalButton(
         'famBagsBagsRefreshButton',
         famBags.famBagsFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags:LayoutBagsButtons('bags')
         end,
         'Interface\\Addons\\famBags\\Textures\\btnrefresh.blp',
         'Interface\\Addons\\famBags\\Textures\\btnrefreshdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Refresh Layout'])
      self.BagsRefreshButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsRefreshButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsRefreshButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsRefreshButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsRefreshButton:Show()
      anchorframe = self.BagsRefreshButton
   elseif self.BagsRefreshButton then
      self.BagsRefreshButton:Hide()
   end

   if db.bagswindow and self.db.profile.bagswindow.enabled then
      self.BagSlotsButton = self.BagSlotsButton or self:CreateCheckButton(
         'famBagsBagSlotsButton',
         famBags.famBagsFrame,
         'Interface\\Addons\\famBags\\Textures\\btnshowbags.blp',
         'Interface\\Addons\\famBags\\Textures\\btnshowbags.blp',
         'Interface\\Addons\\famBags\\Textures\\btnhidebags.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Bag slots on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            if self:GetChecked() then
               famBags.famBagsBagSlotsFrame:Show()
            else
               famBags.famBagsBagSlotsFrame:Hide()
            end
         end)
      self.BagSlotsButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagSlotsButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagSlotsButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagSlotsButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagSlotsButton:Show()
      anchorframe = self.BagSlotsButton
   elseif self.BagSlotsButton then
      self.BagSlotsButton:Hide()
   end

   if db.resetupdated then
      self.BagsResetUpdatedButton = self.BagsResetUpdatedButton or self:CreateNormalButton(
         'famBagsBagsResetUpdatedButton',
         famBags.famBagsFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.Buttons:ResetUpdatedIndicators()
            famBags:LayoutBagsButtons('bags')
         end,
         'Interface\\Addons\\famBags\\Textures\\btnreset.blp',
         'Interface\\Addons\\famBags\\Textures\\btnresetdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Reset updated item indicators'])
      self.BagsResetUpdatedButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsResetUpdatedButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsResetUpdatedButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsResetUpdatedButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsResetUpdatedButton:Show()
      anchorframe = self.BagsResetUpdatedButton
   elseif self.BagsResetUpdatedButton then
      self.BagsResetUpdatedButton:Hide()
   end

   if db.search then
      self.BagsSearchButton = self.BagsSearchButton or self:CreateCheckButton(
         'famBagsBagsSearchButton',
         famBags.famBagsFrame,
         'Interface\\Addons\\famBags\\Textures\\btnsearch.blp',
         'Interface\\Addons\\famBags\\Textures\\btnsearch.blp',
         'Interface\\Addons\\famBags\\Textures\\btnsearchdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Search mode on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.db.profile.bags_searchmode = self:GetChecked() or false
            local f = famBags.BagsSearchFrame
            local db = famBags.db.profile.mainwindow.search
            local offset = f:GetHeight() + db.vpadding
            if famBags.db.profile.bags_searchmode then
               local text = f.edit:GetText()
               famBags.bagsSearchFilter = (text) and strupper(string.gsub(text, "^%s*(.-)%s*$", "%1")) or nil
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:Show()
                  f:SetPoint('BOTTOMRIGHT', f:GetParent(), 'TOPRIGHT', -db.hpadding, db.vpadding)
                  f.aniGroupIn.anipos:SetOffset(0, -offset)
                  f.aniGroupIn.ani:SetOffset(0, offset)
                  f.aniGroupIn:Play()
               else
                  f:Show()
                  famBags:LayoutBagsButtons('bags')
               end
            else
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:SetPoint('BOTTOMRIGHT', f:GetParent(), 'TOPRIGHT', -db.hpadding, db.vpadding)
                  f.aniGroupOut.anipos:SetOffset(0, 0)
                  f.aniGroupOut.ani:SetOffset(0, -offset)
                  f.aniGroupOut:Play()
               else
                  f:Hide()
                  famBags:LayoutBagsButtons('bags')
               end
               famBags.bagsSearchFilter = nil
            end
         end,
         self.db.profile.bags_searchmode or false)
      self.BagsSearchButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsSearchButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsSearchButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsSearchButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsSearchButton:Show()
      anchorframe = self.BagsSearchButton
   elseif self.BagsSearchButton then
      if self.BagsSearchButton:GetChecked() then
         self.BagsSearchButton:Click()
      end
      self.BagsSearchButton:Hide()
   end

   if db.optimize then
      self.BagsOptimizeButton = self.BagsOptimizeButton or self:CreateNormalButton(
         'famBagsBagsOptimizeButton',
         famBags.famBagsFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags:OptimizeStacks('bags')
         end,
         'Interface\\Addons\\famBags\\Textures\\btnrestack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnrestackdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Optimize stacks'])
      self.BagsOptimizeButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsOptimizeButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsOptimizeButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsOptimizeButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsOptimizeButton:Show()
      anchorframe = self.BagsOptimizeButton
   elseif self.BagsOptimizeButton then
      self.BagsOptimizeButton:Hide()
   end

   if self.OFFLINE_ENABLED and db.alts then
      self.BagsAltsButton = self.BagsAltsButton or self:CreateCheckButton(
         'famBagsBagsAltsButton',
         famBags.famBagsFrame,
         'Interface\\Addons\\famBags\\Textures\\btnalts.blp',
         'Interface\\Addons\\famBags\\Textures\\btnalts.blp',
         'Interface\\Addons\\famBags\\Textures\\btnaltsdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Alts mode on/off'],
         function(self)
            ClearCursor()
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.db.profile.bags_altsmode = self:GetChecked() or false
            local f = famBags.BagsAltsFrame
            local db = famBags.db.profile.mainwindow.alts
            local offset = f:GetHeight() + db.vpadding
            if famBags.db.profile.bags_altsmode then
               local text = f.edit:GetValue()
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:Show()
                  f:SetPoint('BOTTOMLEFT', f:GetParent(), 'TOPLEFT', -db.hpadding, db.vpadding)
                  f.aniGroupIn.anipos:SetOffset(0, -offset)
                  f.aniGroupIn.ani:SetOffset(0, offset)
                  f.aniGroupIn:Play()
               else
                  f:Show()
                  famBags:ChangeCurrentPlayer(text, 'bags')
               end
            else
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:SetPoint('BOTTOMLEFT', f:GetParent(), 'TOPLEFT', -db.hpadding, db.vpadding)
                  f.aniGroupOut.anipos:SetOffset(0, 0)
                  f.aniGroupOut.ani:SetOffset(0, -offset)
                  f.aniGroupOut:Play()
               else
                  f:Hide()
                  famBags:ChangeCurrentPlayer(famBags.PLAYER_NAME, 'bags')
               end
            end
         end,
         self.db.profile.bags_altsmode or false)
      self.BagsAltsButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsAltsButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsAltsButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsAltsButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsAltsButton:Show()
      anchorframe = self.BagsAltsButton
   elseif self.BagsAltsButton then
      if self.BagsAltsButton:GetChecked() then
         self.BagsAltsButton:Click()
      end
      self.BagsAltsButton:Hide()
   end

   if db.options then
      self.BagsOptionsButton = self.BagsOptionsButton or self:CreateNormalButton(
         'famBagsBagsOptionsButton',
         famBags.famBagsFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags:LoadOptions()
         end,
         'Interface\\Addons\\famBags\\Textures\\btnoptions.blp',
         'Interface\\Addons\\famBags\\Textures\\btnoptionsdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Options'])
      self.BagsOptionsButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsOptionsButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsOptionsButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsOptionsButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsOptionsButton:Show()
      anchorframe = self.BagsOptionsButton
   elseif self.BagsOptionsButton then
      self.BagsOptionsButton:Hide()
   end

   if db.categories then
      self.BagsCategoriesButton = self.BagsCategoriesButton or self:CreateNormalButton(
         'famBagsBagsBagsCategoriesButtonButton',
         famBags.famBagsFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            if LoadAddOn('famBagsOptions') then
               local famBagsOptions = LibStub('AceAddon-3.0'):GetAddon('famBagsOptions')
               famBagsOptions.Categories:ShowCategoriesConfig()
            end
         end,
         'Interface\\Addons\\famBags\\Textures\\btncategories.blp',
         'Interface\\Addons\\famBags\\Textures\\btncategoriesdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Categories'])
      self.BagsCategoriesButton:SetPoint('TOP', famBags.famBagsFrame.titleFrame, 'TOP', 0, 4)
      self.BagsCategoriesButton:SetPoint('BOTTOM', famBags.famBagsFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BagsCategoriesButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BagsCategoriesButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBagsFrame.titleFrame:GetHeight() - 2, 0)
      self.BagsCategoriesButton:Show()
      anchorframe = self.BagsCategoriesButton
   elseif self.BagsCategoriesButton then
      self.BagsCategoriesButton:Hide()
   end

   -------::::::: Bank Buttons :::::::-------

   self.BankCloseButton = self.BankCloseButton or self:CreateNormalButton(
      'famBagsBankCloseButton',
      famBags.famBankFrame,
      function(self)
         local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
         CloseBankFrame()
      end)
   self.BankCloseButton:SetPoint('TOPRIGHT', famBags.famBankFrame.titleFrame, 'TOPRIGHT', 4, 4)
   self.BankCloseButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
   self.BankCloseButton:SetPoint('LEFT', famBags.famBankFrame.titleFrame, 'RIGHT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
   self.BankCloseButton:Show()
   anchorframe = self.BankCloseButton

   if db.stack then
      self.BankStackButton = self.BankStackButton or self:CreateCheckButton(
         'famBagsBankStackButton',
         famBags.famBankFrame,
         'Interface\\Addons\\famBags\\Textures\\btnnostack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnnostack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnstack.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Stacking mode on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.isStackMode = self:GetChecked()
            famBags.db.profile.stackmode = famBags.isStackMode or false
            famBags.BagsStackButton:SetChecked(self:GetChecked())
            famBags:LayoutBagsButtons()
         end,
         self.isStackMode)
      self.BankStackButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankStackButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankStackButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankStackButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankStackButton:Show()
      anchorframe = self.BankStackButton
   elseif self.BankStackButton then
      self.BankStackButton:Hide()
   end

   if db.refresh then
      self.BankRefreshButton = self.BankRefreshButton or self:CreateNormalButton(
         'famBagsBankRefreshButton',
         famBags.famBankFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags:LayoutBagsButtons('bank')
         end,
         'Interface\\Addons\\famBags\\Textures\\btnrefresh.blp',
         'Interface\\Addons\\famBags\\Textures\\btnrefreshdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Refresh Layout'])
      self.BankRefreshButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankRefreshButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankRefreshButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankRefreshButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankRefreshButton:Show()
      anchorframe = self.BankRefreshButton
   elseif self.BankRefreshButton then
      self.BankRefreshButton:Hide()
   end

   if db.bagswindow and self.db.profile.bankwindow.enabled then
      self.BankSlotsButton = self.BankSlotsButton or self:CreateCheckButton(
         'famBagsBankSlotsButton',
         famBags.famBankFrame,
         'Interface\\Addons\\famBags\\Textures\\btnshowbags.blp',
         'Interface\\Addons\\famBags\\Textures\\btnshowbags.blp',
         'Interface\\Addons\\famBags\\Textures\\btnhidebags.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Bag slots on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            if self:GetChecked() then
               famBags.famBagsBlizzardBankFrame:Show()
            else
               famBags.famBagsBlizzardBankFrame:Hide()
            end
         end)
      self.BankSlotsButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankSlotsButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankSlotsButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankSlotsButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankSlotsButton:Show()
      anchorframe = self.BankSlotsButton
   elseif self.BankSlotsButton then
      self.BankSlotsButton:Hide()
   end

   if db.search then
      self.BankSearchButton = self.BankSearchButton or self:CreateCheckButton(
         'famBagsBankSearchButton',
         famBags.famBankFrame,
         'Interface\\Addons\\famBags\\Textures\\btnsearch.blp',
         'Interface\\Addons\\famBags\\Textures\\btnsearch.blp',
         'Interface\\Addons\\famBags\\Textures\\btnsearchdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Search mode on/off'],
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.db.profile.bank_searchmode = self:GetChecked() or false
            local f = famBags.BankSearchFrame
            local db = famBags.db.profile.bank.search
            local offset = f:GetHeight() + db.vpadding
            if famBags.db.profile.bank_searchmode then
               local text = f.edit:GetText()
               famBags.bankSearchFilter = (text) and strupper(string.gsub(text, "^%s*(.-)%s*$", "%1")) or nil
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:Show()
                  f:SetPoint('BOTTOMRIGHT', f:GetParent(), 'TOPRIGHT', -db.hpadding, db.vpadding)
                  f.aniGroupIn.anipos:SetOffset(0, -offset)
                  f.aniGroupIn.ani:SetOffset(0, offset)
                  f.aniGroupIn:Play()
               else
                  f:Show()
                  famBags:LayoutBagsButtons('bank')
               end
            else
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:SetPoint('BOTTOMRIGHT', f:GetParent(), 'TOPRIGHT', -db.hpadding, db.vpadding)
                  f.aniGroupOut.anipos:SetOffset(0, 0)
                  f.aniGroupOut.ani:SetOffset(0, -offset)
                  f.aniGroupOut:Play()
               else
                  f:Hide()
                  famBags:LayoutBagsButtons('bank')
               end
               famBags.bankSearchFilter = nil
            end
         end,
         self.db.profile.bank_searchmode or false)
      self.BankSearchButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankSearchButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankSearchButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankSearchButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankSearchButton:Show()
      anchorframe = self.BankSearchButton
   elseif self.BankSearchButton then
      if self.BankSearchButton:GetChecked() then
         self.BankSearchButton:Click()
      end
      self.BankSearchButton:Hide()
   end

   if db.optimize then
      self.BankOptimizeButton = self.BankOptimizeButton or self:CreateNormalButton(
         'famBagsBankOptimizeButton',
         famBags.famBankFrame,
         function(self)
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags:OptimizeStacks('bank')
         end,
         'Interface\\Addons\\famBags\\Textures\\btnrestack.blp',
         'Interface\\Addons\\famBags\\Textures\\btnrestackdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Optimize stacks'])
      self.BankOptimizeButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankOptimizeButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankOptimizeButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankOptimizeButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankOptimizeButton:Show()
      anchorframe = self.BankOptimizeButton
   elseif self.BankOptimizeButton then
      self.BankOptimizeButton:Hide()
   end

   if self.OFFLINE_ENABLED and db.alts then
      self.BankAltsButton = self.BankAltsButton or self:CreateCheckButton(
         'famBagsBankAltsButton',
         famBags.famBankFrame,
         'Interface\\Addons\\famBags\\Textures\\btnalts.blp',
         'Interface\\Addons\\famBags\\Textures\\btnalts.blp',
         'Interface\\Addons\\famBags\\Textures\\btnaltsdown.blp',
         'Interface/Buttons/UI-Panel-MinimizeButton-Highlight',
         L['Alts mode on/off'],
         function(self)
            ClearCursor()
            local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
            famBags.db.profile.bank_altsmode = self:GetChecked() or false
            local f = famBags.BankAltsFrame
            local db = famBags.db.profile.bank.alts
            local offset = f:GetHeight() + db.vpadding
            if famBags.db.profile.bank_altsmode then
               local text = f.edit:GetValue()
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:Show()
                  f:SetPoint('BOTTOMLEFT', f:GetParent(), 'TOPLEFT', -db.hpadding, db.vpadding)
                  f.aniGroupIn.anipos:SetOffset(0, -offset)
                  f.aniGroupIn.ani:SetOffset(0, offset)
                  f.aniGroupIn:Play()
               else
                  f:Show()
                  famBags:ChangeCurrentPlayer(text, 'bank')
               end
            else
               if db.animation then
                  f.aniGroupOut:Stop()
                  f.aniGroupIn:Stop()
                  f:SetPoint('BOTTOMLEFT', f:GetParent(), 'TOPLEFT', -db.hpadding, db.vpadding)
                  f.aniGroupOut.anipos:SetOffset(0, 0)
                  f.aniGroupOut.ani:SetOffset(0, -offset)
                  f.aniGroupOut:Play()
               else
                  f:Hide()
                  famBags:ChangeCurrentPlayer(famBags.PLAYER_NAME, 'bank')
               end
            end
         end,
         self.db.profile.bank_altsmode or false)
      self.BankAltsButton:SetPoint('TOP', famBags.famBankFrame.titleFrame, 'TOP', 0, 4)
      self.BankAltsButton:SetPoint('BOTTOM', famBags.famBankFrame.titleFrame, 'BOTTOM', 0, -2)
      self.BankAltsButton:SetPoint('RIGHT', anchorframe, 'LEFT', 5, 0)
      self.BankAltsButton:SetPoint('LEFT', anchorframe, 'LEFT', -famBags.famBankFrame.titleFrame:GetHeight() - 2, 0)
      self.BankAltsButton:Show()
      anchorframe = self.BankAltsButton
   elseif self.BankAltsButton then
      if self.BankAltsButton:GetChecked() then
         self.BankAltsButton:Click()
      end
      self.BankAltsButton:Hide()
   end

   self.BagsSearchFrame = self.BagsSearchFrame or self:CreateInputFrame('bags', 'search')
   self.BankSearchFrame = self.BankSearchFrame or self:CreateInputFrame('bank', 'search')
   self.BagsOptimizationProgress = self.BagsOptimizationProgress or self:CreateOptimizationProgress('bags', self.BagsOptimizeButton)
   self.BankOptimizationProgress = self.BankOptimizationProgress or self:CreateOptimizationProgress('bank', self.BankOptimizeButton)
   if self.OFFLINE_ENABLED then
      self.BagsAltsFrame = self.BagsAltsFrame or self:CreateInputFrame('bags', 'alts')
      self.BankAltsFrame = self.BankAltsFrame or self:CreateInputFrame('bank', 'alts')
   end
end

function famBags:CreateInputFrame(bag, kind)
   local function start_anim(self)
      local f = self:GetRegionParent()
      f.borderbck = f:GetBackdrop(nil)
      f:SetBackdrop(nil)
   end
   local function end_anim(self)
      local f = self:GetRegionParent()
      f:SetBackdrop(f.borderbck)
      if self:IsDone() then
         if kind == 'search' then
            famBags:LayoutBagsButtons(f.edit.bag)
         else
            famBags:ChangeCurrentPlayer(f.edit:GetValue(), f.edit.bag)
         end
      end
   end
   local function end_anim_hide(self)
      local f = self:GetRegionParent()
      f:SetBackdrop(f.borderbck)
      f:Hide()
      if self:IsDone() then
         if kind == 'search' then
            famBags:LayoutBagsButtons(f.edit.bag)
         else
            famBags:ChangeCurrentPlayer(famBags.PLAYER_NAME, f.edit.bag)
         end
      end
   end

   local db = (bag == 'bags') and db.mainwindow or db.bank
   if kind == 'search' then
      db = db.search
   else
      db = db.alts
   end
   local name = 'famBags'..((bag == 'bags') and 'Bags' or 'Bank')..((kind == 'search') and 'SearchFrame' or 'AltsFrame')
   local parent = self.MAINFRAMES[bag]
   local f = CreateFrame('Frame', name, parent)
   --f:SetFrameStrata(db.strata)
   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetWidth(206)
   if kind == 'search' then
      f:SetHeight(30)
   else
      f:SetHeight(36)
   end
   f:SetFrameLevel(db.level)
   if kind == 'search' then
      f:SetPoint('BOTTOMRIGHT', parent, 'TOPRIGHT', -db.hpadding, db.vpadding)
   else
      f:SetPoint('BOTTOMLEFT', parent, 'TOPLEFT', db.hpadding, db.vpadding)
   end
   self:SetFrameBackdrop(f, db)

   if kind == 'search' then
      f.edit = AceGUI:Create("EditBox")
      f.edit.frame:SetParent(f)
      f.edit:SetText("")
      f.edit:SetWidth(200)
      f.edit:SetPoint('LEFT', f, 'LEFT', 5, 0)
      f.edit:SetPoint('RIGHT', f, 'RIGHT', -5, 0)
      f.edit:SetCallback("OnEnterPressed",function(widget,event,text)
         local index = widget.bag..'SearchFilter'
         famBags[index] = (text) and strupper(string.gsub(text, "^%s*(.-)%s*$", "%1")) or nil
         if famBags[index] == '' then
            famBags[index] = nil
         end
         famBags:LayoutBagsButtons(widget.bag)
      end)
      f.edit.bag = bag
      f.edit.frame:Show()
   else
      f.edit = AceGUI:Create("Dropdown")
      f.edit.frame:SetParent(f)
      f.edit:SetText("")
      f.edit:SetList(self.CHARACTERS)
      if not next(self.CHARACTERS) then
         f.edit:SetDisabled(true)
      end
      f.edit:SetWidth(200)
      f.edit:SetPoint('LEFT', f, 'LEFT', 2, 2)
      f.edit:SetPoint('RIGHT', f, 'RIGHT', -5, 2)
      f.edit:SetCallback("OnValueChanged",function(widget,event,text)
         famBags:ChangeCurrentPlayer(text, widget.bag)
      end)
      f.edit.frame:SetHeight(24)
      f.edit.bag = bag
      f.edit.frame:Show()
   end

   f.aniGroupIn = f:CreateAnimationGroup()
   f.aniGroupIn.anipos = f.aniGroupIn:CreateAnimation("Translation")
   f.aniGroupIn.anipos:SetDuration(0)
   f.aniGroupIn.anipos:SetOffset(0, 0)
   f.aniGroupIn.ani = f.aniGroupIn:CreateAnimation("Translation")
   f.aniGroupIn.ani:SetDuration(0.2)
   f.aniGroupIn.ani:SetSmoothing("IN")
   f.aniGroupIn.ani:SetOffset(0, 0)
   f.aniGroupIn.ani:SetScript("OnPlay", start_anim)
   f.aniGroupIn.ani:SetScript("OnFinished", end_anim)
   f.aniGroupIn.ani:SetScript("OnStop", end_anim)

   f.aniGroupOut = f:CreateAnimationGroup()
   f.aniGroupOut.anipos = f.aniGroupIn:CreateAnimation("Translation")
   f.aniGroupOut.anipos:SetDuration(0)
   f.aniGroupOut.anipos:SetOffset(0, 0)
   f.aniGroupOut.ani = f.aniGroupOut:CreateAnimation("Translation")
   f.aniGroupOut.ani:SetDuration(0.2)
   f.aniGroupOut.ani:SetSmoothing("OUT")
   f.aniGroupOut.ani:SetOffset(0, 0)
   f.aniGroupOut.ani:SetScript("OnPlay", start_anim)
   f.aniGroupOut.ani:SetScript("OnFinished", end_anim_hide)
   f.aniGroupOut.ani:SetScript("OnStop", end_anim_hide)

   if self.db.profile[bag..'_'..kind..'mode'] then
      f:Show()
   else
      f:Hide()
   end
   return f
end

function famBags:UpdateInputFrame(frame, db)
   local parent = frame:GetParent()
   frame:SetFrameLevel(db.level)
   frame:SetWidth(parent:GetWidth() * db.width)
   if frame == self.BagsSearchFrame or frame == self.BankSearchFrame then
      frame:SetPoint('BOTTOMRIGHT', parent, 'TOPRIGHT', -db.hpadding, db.vpadding)
   else
      frame:SetPoint('BOTTOMLEFT', parent, 'TOPLEFT', -db.hpadding, db.vpadding)
   end
 --   self:SetFrameBackdrop(frame, db)
end

function famBags:CreateOptimizationProgress(bag, anchor)
   local name = 'famBags'..((bag == 'bags') and 'Bags' or 'Bank')..'OptimizationProgress'
   local f = CreateFrame('Frame', name, (bag == 'bags') and self.famBagsFrame or self.famBankFrame)
   f:SetFrameStrata(self.db.profile.layout.general.strata)
   if f:GetEffectiveScale() == 1 then
      f:SetScale(UIParent:GetEffectiveScale())
   end
   f:SetWidth(206)
   f:SetHeight(37)
   f:SetFrameLevel(20)
   f:SetPoint('TOPLEFT', anchor, 'BOTTOM', -37, 15)

   f.body = CreateFrame('Frame', name..'Body', f, 'GlowBoxTemplate')
   f.body:SetPoint('TOPLEFT', f, 'TOPLEFT', 0, -20)
   f.body:SetPoint('BOTTOMRIGHT', f, 'BOTTOMRIGHT', 0, 0)
   f.body:Show()

   f.arrow = CreateFrame('Frame', name..'Arrow', f, 'GlowBoxArrowTemplate')
   f.arrow:SetWidth(53)
   f.arrow:SetHeight(-21)
   f.arrow:SetPoint('TOPLEFT', f, 'TOPLEFT', 10, 0)
   local t = _G[name..'ArrowGlow']
   local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy = t:GetTexCoord()
   t:SetTexCoord(ULx, LLy, LLx, ULy, URx, LRy, LRx, URy)
   t:SetPoint('TOP', f.arrow, 'TOP', 0, 7)
   t = _G[name..'ArrowArrow']
   ULx, ULy, LLx, LLy, URx, URy, LRx, LRy = t:GetTexCoord()
   t:SetTexCoord(ULx, LLy, LLx, ULy, URx, LRy, LRx, URy)
   t:SetPoint('TOP', f.arrow, 'TOP', 0, 0)
   f.arrow:Show()

   f.bar = CreateFrame('Frame', name..'Bar', f)
   f.bar:SetWidth(200)
   f.bar:SetHeight(11)
   f.bar:SetPoint('TOPLEFT', f.body, 'TOPLEFT', 3, -3)
   t = f.bar:CreateTexture()
   t:SetTexture('Interface/Buttons/GradBlue')
   t:SetAllPoints()
   f.bar:Show()

   f:Hide()

   return f
end

function famBags:StartOptimizationProgress(bag)
   local f = (bag == 'bags') and self.BagsOptimizationProgress or self.BankOptimizationProgress
   f.bar:SetWidth(0)
   f:Show()
end

function famBags:SetOptimizationProgress(bag, progress)
   local f = (bag == 'bags') and self.BagsOptimizationProgress or self.BankOptimizationProgress
   f.bar:SetWidth(200 * progress)
end

function famBags:StopOptimizationProgress(bag)
   local f = (bag == 'bags') and self.BagsOptimizationProgress or self.BankOptimizationProgress
   f:Hide()
end

function famBags:ToggleBagSlotsButtonStatus(bag)
   local collecting = ((bag == 'bags') and db.bagswindow.enabled) or ((bag == 'bank') and db.bankwindow.enabled)
   if collecting and db.layout.actions.bagswindow then
      local b = (bag == 'bags') and self.BagSlotsButton or self.BankSlotsButton
      if self.MAINFRAMES[bag].offline then
         if b:GetChecked() then
            b:Click()
         else
            local frame = (bag == 'bags') and famBags.famBagsBagSlotsFrame or famBags.famBagsBlizzardBankFrame
            frame:Hide()
         end
         b:Disable()
      else
         b:Enable()
      end
   end
end

function famBags:ToggleOptimizeButtonStatus(bag)
   if db.layout.actions.optimize then
      local b = (bag == 'bags') and self.BagsOptimizeButton or self.BankOptimizeButton
      if self.MAINFRAMES[bag].offline then
         b:Disable()
      else
         b:Enable()
      end
   end
end

function famBags:ToggleRefreshButtonStatus(bag)
   if db.layout.actions.refresh then
      local b = (bag == 'bags') and self.BagsRefreshButton or self.BankRefreshButton
      if self.MAINFRAMES[bag].offline then
         b:Disable()
      else
         b:Enable()
      end
   end
end

function famBags:ToggleResetUpdatedButtonStatus()
   if db.layout.actions.resetupdated then
      if self.MAINFRAMES['bags'].offline then
         self.BagsResetUpdatedButton:Disable()
      else
         self.BagsResetUpdatedButton:Enable()
      end
   end
end

function famBags:ChangeCurrentPlayer(player, bag)
   if not self.ForceCurrentPlayerChange[bag] and (not player or self.CURRENT_PLAYER[bag] == player) then return end
   self.ForceCurrentPlayerChange[bag] = nil
   self.MAINFRAMES[bag].offline = ((bag == 'bank' and not self.IsBankOpen) or player ~= self.PLAYER_NAME)
   self.CURRENT_PLAYER[bag] = player
   famBags.Buttons:ClearDBButtons(bag)
   local title
   local dbt
   if bag == 'bags' then
      famBags.BAGS_NEED_LAYOUT = true
      title = L['famBags']
      dbt = db.mainwindow.title.text
      self:ToggleResetUpdatedButtonStatus()
      if self.MAINFRAMES[bag].offline then
         self:UpdateOfflineCurrency()
      else
         self:UpdateCurrency()
      end
   elseif bag == 'bank' then
      famBags.BANK_NEED_LAYOUT = true
      title = L['Bank']
      dbt = db.bank.title.text
   end
   self:ToggleBagSlotsButtonStatus(bag)
   self:ToggleOptimizeButtonStatus(bag)
   self:ToggleRefreshButtonStatus(bag)
   local subfix = (self.MAINFRAMES[bag].offline) and ' ['..L['offline']..']' or ''
   self:SetTextLayout(self.MAINFRAMES[bag].titleFrame, self.MAINFRAMES[bag].titleFrame.titleText, dbt, title..subfix)
   self.EMPTIES_NEED_LAYOUT[bag] = true
   for _, i in ipairs(self.BagIndexes[bag]) do
      if famBags.Buttons[i] then
         if #famBags.Buttons[i] > 0 then
            for j = 1, #famBags.Buttons[i] do
               local b = famBags.Buttons[i][j]
               b:Hide()
               famBags.Buttons[i][j] = nil
            end
         else
            famBags.Buttons[i] = nil
         end
      end
   end
   self:UpdatePlayerBags(bag)
   self:UpdateEmptiesButtons(bag)
   self.Buttons:UpdateEmpties(bag)
end

--[[
function famBags:OnDisable()
end

SLASH_FAMBAGS1 = '/fambags'
SlashCmdList['FAMBAGS'] = function(msg, editbox)
end
--]]
